#ifndef __SYLAR_ADDRESS_H__
#define __SYLAR_ADDRESS_H__

#include <memory>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <map>

namespace sylar{

class IPAddress;
/**
 * @brief 地址类的封装
 */
class Address {

public:
	typedef std::shared_ptr<Address> ptr;
	/**
	 * 创建一个地址(IPv4, IPv6)
	 */
	static Address::ptr Create(const sockaddr* addr, socklen_t len);
	/**
	 * @brief 查询对应的地址
	 */
	static bool Lookup(std::vector<Address::ptr>& result, const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);
	static Address::ptr LookupAny(const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);
	static std::shared_ptr<IPAddress> LookupAnyIPAddress(const std::string& host, int family = AF_INET, int type = 0, int protocol = 0);
	/**
	 * @brief 查询网卡地址
	 */
	static bool GetInterfaceAddress(std::multimap<std::string, std::pair<Address::ptr, uint32_t> >& result, int family = AF_INET);
	static bool GetInterfaceAddress(std::vector<std::pair<Address::ptr, uint32_t> >&results, const std::string& iface, int family = AF_INET);
	virtual ~Address(){}
	
	int getFamily() const;
	virtual const sockaddr* getAddr() const = 0;
	virtual sockaddr* getAddr() = 0;
	virtual socklen_t getAddrLen() const = 0;
	
	virtual std::ostream& insert(std::ostream& os) const = 0;
	std::string toString() const;

	bool operator<(const Address& rhs) const;
	bool operator==(const Address& rhs) const;
	bool operator!=(const Address& rhs) const;
};

class IPAddress : public Address{
public:
	typedef std::shared_ptr<IPAddress> ptr;
	
	static IPAddress::ptr Create(const char* address, uint16_t port = 0);

	virtual IPAddress::ptr boardcastAddress(uint32_t prefix_len) = 0;
	virtual IPAddress::ptr networkAddress(uint32_t prefix_len) = 0;
	virtual IPAddress::ptr subnetMask(uint32_t prefix_len) = 0;

	virtual uint16_t getPort() const = 0;
	virtual void setPort(uint16_t v) = 0;
};

class IPv4Address : public IPAddress{
public:
	typedef std::shared_ptr<IPv4Address> ptr;

	static IPv4Address::ptr Create(const char* address, uint16_t port = 0);

	IPv4Address(sockaddr_in addr);
	IPv4Address(uint32_t address = INADDR_ANY, uint16_t port = 0);
	
	const sockaddr* getAddr() const override;
	sockaddr* getAddr() override;
	socklen_t getAddrLen() const override;
	std::ostream& insert(std::ostream& os) const override;

	IPAddress::ptr boardcastAddress(uint32_t prefix_len) override;
	IPAddress::ptr networkAddress(uint32_t prefix_len) override;
	IPAddress::ptr subnetMask(uint32_t prefix_len) override;

	virtual uint16_t getPort() const override;
	virtual void setPort(uint16_t v) override;
private:
	sockaddr_in m_addr;
};

class IPv6Address : public IPAddress{
public:
	typedef std::shared_ptr<IPv6Address> ptr;
	static IPv6Address::ptr Create(const char* address, uint16_t port = 0);
	IPv6Address();
	IPv6Address(sockaddr_in6 addr);
	IPv6Address(const char* address, uint16_t port = 0);
	IPv6Address(const uint8_t address[16], uint16_t port = 0);
	
	const sockaddr* getAddr() const override;
	sockaddr* getAddr() override;
	socklen_t getAddrLen() const override;
	std::ostream& insert(std::ostream& os) const override;

	IPAddress::ptr boardcastAddress(uint32_t prefix_len) override;
	IPAddress::ptr networkAddress(uint32_t prefix_len) override;
	IPAddress::ptr subnetMask(uint32_t prefix_len) override;

	virtual uint16_t getPort() const override;
	virtual void setPort(uint16_t v) override;
private:
	sockaddr_in6 m_addr;
};


class UnixAddress : public Address{
public:	
	typedef std::shared_ptr<UnixAddress> ptr;
	UnixAddress();
	UnixAddress(const std::string& path);

	const sockaddr* getAddr() const override;
	sockaddr* getAddr() override;
	socklen_t getAddrLen() const override;
	void setAddrLen(uint32_t v);
	std::string getPath() const;
	std::ostream& insert(std::ostream& os) const override;
private:
	sockaddr_un m_addr;
	socklen_t m_length;
};

class UnknowAddress : public Address{
public:
	typedef	std::shared_ptr<UnknowAddress> ptr;
	UnknowAddress(int family);
	UnknowAddress(const sockaddr& addr);
	const sockaddr* getAddr() const override;
	sockaddr* getAddr() override;
	socklen_t getAddrLen() const override;
	std::ostream& insert(std::ostream& os) const override;
private:
	sockaddr m_addr;
};

std::ostream& operator<<(std::ostream& os, const Address& addr);

}


#endif